﻿using Seagull.BarTender.Print;
using Seagull.BarTender.Print.Database;
using System;
using System.Collections.Generic;
using System.Drawing.Printing;
using System.IO;

namespace PrintService
{
    public static class PrintHelper
    {
        public static string DefaultPrinter { get; set; }
        private static object _lockObject = new object();
        private static string UsedPrinter {
            get{
                return (ServiceConstants.UseDefaultPrinter && !string.IsNullOrEmpty(DefaultPrinter) && DefaultPrinter.StartsWith("Gprinter"))
                    ? DefaultPrinter : ServiceConstants.PrinterName;
            }
        }

        public  static bool SaveDataAsFile(string content, string filePath)
        {
            try
            {
                byte[] dataBytes = System.Text.Encoding.GetEncoding("GBK").GetBytes(content);
                using (FileStream stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                {
                    stream.Write(dataBytes, 0, dataBytes.Length);
                    stream.Close();
                }

                LogHelper.LogInfo(string.Format("Data is successfully saved to a file({0}).", filePath));
                return true;
            }
            catch (Exception ex)
            {
                LogHelper.LogError(string.Format("Error occurred when save data as file. Error: {0}", ex.Message));
                return false;
            }
        }

        public static string DoPrint(string filePath, string templateName = null)
        {
            LogHelper.LogInfo("Start to print.");
            LogHelper.LogInfo($"File full path: {filePath}.");

            lock (_lockObject)
            { 
                try
                {
                    if (string.IsNullOrEmpty(templateName)) {
                        var fileName = Path.GetFileName(filePath);
                        templateName = fileName.Substring(0, fileName.LastIndexOf("_"));
                    }
                    var templatePath = Path.Combine(ServiceConstants.TemplateFolder, templateName);

                    if (!File.Exists(templatePath))
                    {
                        var errorInfo = string.Format("Template({0}) does not exist.", templatePath);
                        LogHelper.LogError(errorInfo);
                        return errorInfo;
                    }

                    if (!VerifyPrinter(UsedPrinter))
                    {
                        var errorInfo = string.Format("Printer({0}) is not installed, please specify a useful printer.", UsedPrinter);
                        LogHelper.LogError(errorInfo);
                        return errorInfo;
                    }

                    using (Engine engine = new Engine())
                    {
                        engine.Start();
                        LabelFormatDocument labelFormat = engine.Documents.Open(templatePath, UsedPrinter);

                        //设置数据源
                        ((TextFile)labelFormat.DatabaseConnections[0]).FileName = filePath;

                        //如果打印时发生共享错误，重试打印，每次重试前休眠0.5秒等待文件写入完成，最多重试三次
                        Messages messages;
                        int waitout = 3000; // 5 seconds
                        Result nResult;
                        int retryCounter = 0;
                        string messageString = "\n\nMessages:";
                        do
                        {
                            if (retryCounter > 0) { System.Threading.Thread.Sleep(500); LogHelper.LogInfo($"第{retryCounter.ToString()}次重试"); }
                            retryCounter += 1;

                            nResult = labelFormat.Print(string.Format("Print {0}", Path.GetFileName(templatePath)), waitout, out messages);
                            messageString = "\n\nMessages:";
                            labelFormat.PrintSetup.Cache.FlushInterval = CacheFlushInterval.PerSession;
                            foreach (Message message in messages)
                            {
                                messageString += "\n\n" + message.Text;
                            }
                        } while (retryCounter <= 3 && nResult != Result.Success && messageString.IndexOf("发生了共享冲突") >= 0);

                        LogHelper.LogInfo(messageString);
                        labelFormat.Close(SaveOptions.DoNotSaveChanges);
                        engine.Stop();
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.LogError(string.Format("Error occurred when print file. Error: {0}", ex.Message));
                    return ex.Message;
                }
            }

            LogHelper.LogInfo(string.Format("Print completed.{0}", Environment.NewLine));
            return string.Empty;
        }

        /// <summary>
        /// 确认打印机是否存在
        /// </summary>
        /// <param name="printer"></param>
        /// <returns></returns>
        private static bool VerifyPrinter(string printer)
        {
            bool exists = false;
            foreach (string installedPrinter in PrinterSettings.InstalledPrinters)
            {
                if (printer.Equals(installedPrinter))
                {
                    exists = true;
                    break;
                }
            }
            return exists;
        }

        public static bool TestPrint(string printer) {
            try
            {
                using (Engine engine = new Engine())
                {
                    var availablePrinterBrands = ServiceConstants.PrinterBrands.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                    var testTemplates = ServiceConstants.TestTemplates.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                    var index = -1;
                    for (var i = 0; i < availablePrinterBrands.Length; i++) {
                        if (printer.Contains(availablePrinterBrands[i])) {
                            index = i;
                            break;
                        }
                    }

                    if (index < 0) {
                        LogHelper.LogInfo("Cannot find printer from available printer brands");
                        return false;
                    }

                    var templateName = testTemplates?[index];
                    if (string.IsNullOrEmpty(templateName)) {
                        LogHelper.LogInfo($"Cannot find test template from test templates, index: {index}");
                        return false;
                    }

                    var templatePath = Path.Combine(ServiceConstants.TemplateFolder, templateName);

                    engine.Start();
                    LabelFormatDocument labelFormat = engine.Documents.Open(templatePath, printer);
                    labelFormat.PrintSetup.EnablePrompting = false;

                    Messages messages;
                    int waitout = 5000; // 10 seconds
                    Result nResult = labelFormat.Print("Test to print", waitout, out messages);
                    labelFormat.PrintSetup.Cache.FlushInterval = CacheFlushInterval.PerSession;
                    string messageString = "\n\nMessages:";
                    foreach (Message message in messages)
                    {
                        messageString += "\n\n" + message.Text;
                    }
                    LogHelper.LogInfo(messageString);
                    labelFormat.Close(SaveOptions.DoNotSaveChanges);
                    engine.Stop();
                    return nResult == Result.Success;
                }
            }
            catch (Exception e)
            {
                LogHelper.LogInfo(e.Message);
                return false;
            }
        }
    }
}
